﻿#ifndef __INC_KSTUB_MUTEX_H__
#define __INC_KSTUB_MUTEX_H__

#if _MSC_VER
#pragma once
#endif

#if _SB_PTHREAD_

#if _SB_WINDOWS_
#include "posix/pthread.h"
#else
#include <pthread.h>
#endif

extern pthread_mutexattr_t* k_mutexattr(void);
extern pthread_condattr_t* k_condattr(void);

#define STUB_MUTEX pthread_mutex_t

K_INLINE kcham stub_mutex_init(STUB_MUTEX* mutex, kuint spincount)
{
	(void)spincount;
	return pthread_mutex_init(mutex, k_mutexattr()) == 0;
}

K_INLINE void stub_mutex_disp(STUB_MUTEX* mutex)
{
	pthread_mutex_destroy(mutex);
}

K_INLINE void stub_mutex_enter(STUB_MUTEX* mutex)
{
	pthread_mutex_lock(mutex);
}

K_INLINE void stub_mutex_leave(STUB_MUTEX* mutex)
{
	pthread_mutex_unlock(mutex);
}

#elif _SB_WINDOWS_

#define STUB_MUTEX	CRITICAL_SECTION

K_INLINE kcham stub_mutex_init(STUB_MUTEX* cs, kuint spincount)
{
	kcham ret;

	if (spincount == 0)
	{
#if _SB_WINDOWS_DESKTOP_
		InitializeCriticalSection(cs);
		ret = TRUE;
#else
		ret = InitializeCriticalSectionEx(cs, 0, 0) != 0;
#endif
	}
	else
	{
#if _MSC_VER
		__try
		{
#if _SB_WINDOWS_DESKTOP_
			ret = InitializeCriticalSectionAndSpinCount(cs, spincount) != 0;
#else
			ret = InitializeCriticalSectionEx(cs, spincount, 0) != 0;
#endif
		}
		__except (_exception_code() == STATUS_NO_MEMORY ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
		{
			if (GetExceptionCode() == STATUS_NO_MEMORY)
			{
				SetLastError(ERROR_NOT_ENOUGH_MEMORY);
				errno = ENOMEM;
			}
			ret = FALSE;
		}
#else
		ret = InitializeCriticalSectionAndSpinCount(cs, spincount);
#endif
	}

	return ret;
}

K_INLINE void stub_mutex_disp(STUB_MUTEX* cs)
{
	DeleteCriticalSection(cs);
}

K_INLINE void stub_mutex_enter(STUB_MUTEX* cs)
{
	EnterCriticalSection(cs);
}

K_INLINE void stub_mutex_leave(STUB_MUTEX* cs)
{
	LeaveCriticalSection(cs);
}

#else

// 알 수 없음
#error unknown thread target

#endif	// _SB_PTHREAD_

#endif	// __INC_KSTUB_MUTEX_H__
